import { Graph, FunctionExt, Shape, Addon } from '@antv/x6'
import './shape'
import NodeType from '@/constant/nodeType'
export default class FlowGraph {
  // 类构造方法
  constructor() {
    this.initGraph()
    this.initStencil()
    this.initShape()
    this.initGraphShape()
    this.initEvent()
  }

  // 初始化面板
  initGraph() {
    this.graph = new Graph({
      container: document.getElementById('container'),
      width: '100%',
      height: 800,
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
        showNodeSelectionBox: true
      },
      grid: {
        size: 10,
        visible: true
      },
      background: {
        color: '#f7f8fc'
      },
      resizing: {
        enabled: false
      },
      connecting: {
        snap: true,
        allowBlank: false,
        allowLoop: false,
        highlight: true,
        connectionPoint: 'boundary',
        // 连线
        createEdge({ sourceCell, sourceView, sourceMagnet }) {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: '#5F95FF',
                strokeWidth: 1,
                targetMarker: {
                  name: 'classic',
                  size: 8
                }
              }
            },
            router: {
              name: 'manhattan'
            }
          })
        },
        validateConnection({
          sourceView,
          targetView,
          sourceMagnet,
          targetMagnet
        }) {
          if (sourceView === targetView) {
            return false
          }
          if (!sourceMagnet) {
            return false
          }
          if (!targetMagnet) {
            return false
          }
          return true
        }
      },
      highlighting: {
        magnetAvailable: {
          name: 'stroke',
          args: {
            padding: 4,
            attrs: {
              strokeWidth: 4,
              stroke: 'rgba(223,234,255)'
            }
          }
        }
      },
      snapline: true,
      history: true,
      clipboard: {
        enabled: true
      },
      keyboard: {
        enabled: true
      },
      embedding: {
        enabled: true,
        findParent({ node }) {
          const bbox = node.getBBox()
          return this.getNodes().filter((node) => {
            // 只有 data.parent 为 true 的节点才是父节点
            const data = node.getData()
            if (data && data.parent) {
              const targetBBox = node.getBBox()
              return bbox.isIntersectWithRect(targetBBox)
            }
            return false
          })
        }
      }
    })
  }

  // 初始化左侧组件
  initStencil() {
    this.stencil = new Addon.Stencil({
      target: this.graph,
      stencilGraphWidth: 280,
      collapsable: true,
      groups: [
        {
          name: 'basic',
          title: '流程节点',
          graphHeight: 680,
          layoutOptions: {
            columns: 1,
            marginX: 60,
            rowHeight: 120
          }

        }
      ],
      validateNode: node => {
        // 拖入节点之后处理 控制节点大小
        // 如果是条件模块
        if (node.angle() === 45) {
          node.size(60, 60)
        }
        const title = this.getNodeTitle(node.data.NodeType)
        node.setData({ title }) // 设置名称
        node.setAttrs({
          text: {
            text: `点击节点配置`
          },
          title: {
            text: title
          }
        })
      }
    })
    const stencilContainer = document.querySelector('#stencil')
    if (stencilContainer) {
      stencilContainer.appendChild(this.stencil.container)
    }
  }
  // 获取节点的名称
  getNodeTitle(type) {
    if (type === NodeType.CONDITION) {
      return '条件'
    } else if (type === NodeType.SEND_MAN) {
      return '抄送人'
    } else if (type === NodeType.APPRPVAL_MAN) {
      return '审批人'
    }
  }
  // 数据加载给面板和左侧组件输出化数据
  initShape() {
    // 审批人节点
    const conditionMan = this.graph.createNode({
      shape: 'flow-chart-condition',
      data: {
        NodeType: NodeType.CONDITION // 条件类型
      }
    })
    // 审批人节点
    const approvalMan = this.graph.createNode({
      shape: 'flow-chart-title-rect',
      attrs: {
        title: {
          text: '审批人节点'
        },
        head: {
          fill: '#ff943e'
        }
      },
      data: {
        // 节点类型  审批人
        NodeType: NodeType.APPRPVAL_MAN,
        options: {
          multiApproveMode: 2
        }
      }
    })
    // 抄送人节点
    const sendMan = this.graph.createNode({
      shape: 'flow-chart-title-rect',
      attrs: {
        title: {
          text: '抄送人节点',
          background: '#3296fa'
        },
        text: {
          text: '抄送人'
        }
      },
      data: {
        // 节点类型 抄送人
        NodeType: NodeType.SEND_MAN
      }
    })
    this.stencil.load([approvalMan, sendMan, conditionMan], 'basic')
  }

  // 面板渲染
  initGraphShape() {
  }
  // 连接点显示
  showPorts(ports, show) {
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }

  // 初始化事件
  initEvent() {
    const { graph } = this
    const container = document.getElementById('container')
    graph.on('node:contextmenu', ({ cell, view }) => {
      const oldText = cell.attr('text/text')
      cell.attr('text/style/display', 'none')
      const elem = view.container.querySelector('.x6-edit-text')
      if (elem) {
        elem.innerText = oldText
        elem.focus()
      }
      const onBlur = () => {
        cell.attr('text/text', elem.innerText)
      }
      elem.addEventListener('blur', () => {
        onBlur()
        elem.removeEventListener('blur', onBlur)
      })
    })
    graph.on('node:mouseenter', FunctionExt.debounce(() => {
      const ports = container.querySelectorAll('.x6-port-body')
      this.showPorts(ports, true)
    }), 500)
    graph.on('node:mouseleave', () => {
      const ports = container.querySelectorAll(
        '.x6-port-body'
      )
      this.showPorts(ports, false)
    })

    graph.on('node:collapse', ({ node, e }) => {
      e.stopPropagation()
      node.toggleCollapse()
      const collapsed = node.isCollapsed()
      const cells = node.getDescendants()
      cells.forEach((n) => {
        if (collapsed) {
          n.hide()
        } else {
          n.show()
        }
      })
    })

    graph.bindKey('backspace', () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.removeCells(cells)
      }
    })
  }
}
